package com.thrift.distributed.process;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.thrift.distributed.constant.DistributedEnum;
import com.thrift.distributed.entity.BtChargeManagement;
import com.thrift.distributed.entity.BtParamLog;
import com.thrift.distributed.service.IBtChargeManagementService;
import com.thrift.distributed.service.IBtParamLogService;
import com.thrift.distributed.vo.DistributedLogVo;
import com.thrift.distributed.vo.DistributedResultVo;
import com.thrift.distributed.vo.DistributedVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Created by 张波 on 2019/9/18.
 */
@Component
public class DistributedComponent {

    @Autowired
    private IBtChargeManagementService btChargeManagementService;

    @Autowired
    private IBtParamLogService btParamLogService;

    @Autowired
    private FeeFreeCycleComponent feeFreeCycleComponent;

    private DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 保存调用日志
     *
     * @param distributedLogVo
     */
    @Transactional
    public void sendLog(DistributedLogVo distributedLogVo) {
        BtParamLog btParamLog = new BtParamLog();
        btParamLog.setAppid(distributedLogVo.getAppId())
                .setInterfaceName(distributedLogVo.getInterfaceName())
                .setParamValue(distributedLogVo.getParamValue())
                .setResultValue(distributedLogVo.getResultValue())
                .setResetRule(distributedLogVo.getResetRule())
                .setFreeCycle(distributedLogVo.getFreeCycle())
                .setCreateTime(LocalDateTime.now());
        btParamLogService.save(btParamLog);
    }

    /**
     * 服务回退
     *
     * @param distributedVo
     */
    @Transactional
    public void returnCount(DistributedVo distributedVo) {
        /*1、检查是否需要回退面计费日志，若需要，则删除日志*/
        boolean isDel = feeFreeCycleComponent.delRecord(distributedVo);
        if (!isDel) {
            /*如果没有待清理的记录，并且正常场景需要清理的但未查询到要清理的记录，则不回退*/
            return;
        }
        /*2、将可用次数累加1，使用次数减1（大于0才减）*/
        BtChargeManagement chargeManagement = getBtChargeManagement(distributedVo);
        if (null != chargeManagement) {
            boolean updateFlag = true;
            do {
                updateFlag = callBackUpdate(chargeManagement);
                /*更新成功则结束，更新失败则重试*/
                if (!updateFlag) {
                    chargeManagement = getBtChargeManagement(distributedVo);
                }
            } while (!updateFlag);

        }
    }

    /**
     * 根据appid和接口名称查询收费管理对象
     *
     * @param distributedVo
     * @return
     */
    private BtChargeManagement getBtChargeManagement(DistributedVo distributedVo) {
        BtChargeManagement btChargeManagement = new BtChargeManagement();
        btChargeManagement.setAppid(distributedVo.getAppId());
        btChargeManagement.setInterfaceName(distributedVo.getInterfaceName());
        btChargeManagement.setDelInd(DistributedEnum.DATA_STATUS_ENUM.VALID.getCode());
        return btChargeManagementService.getOne(new QueryWrapper<>(btChargeManagement));
    }

    /**
     * 回退更新操作
     *
     * @param chargeManagement
     */
    private boolean callBackUpdate(BtChargeManagement chargeManagement) {
        if (chargeManagement == null) {
            /*对象已经不存在了，则不回退*/
            return true;
        }
        if (chargeManagement.getCurrentUsage() <= 0) {
            /*本周期可用次数为0次，说明还没使用过，则不回退*/
            return true;
        }
        if (DistributedEnum.RESETRULE_ENUM.UNLIMITED.getCode().equals(chargeManagement.getResetRule())) {
            /*如果是无限制类型的，则不回退*/
            return true;
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        if (chargeManagement.getEffectiveDate().isAfter(localDateTime) || chargeManagement.getExpirationDate().isBefore(localDateTime)) {
            /*失效或者未生效，不回退*/
            return true;
        }
        /*回退场景：本周期使用次数-1，可用次数+1*/
        chargeManagement.setCurrentUsage(chargeManagement.getCurrentUsage() - 1);
        chargeManagement.setUsableCount(chargeManagement.getUsableCount() + 1);
        chargeManagement.setUpdateTime(LocalDateTime.now());
        return btChargeManagementService.updateById(chargeManagement);
    }

    /**
     * 规则检测
     *
     * @param distributedVo
     * @return
     */
    @Transactional
    public DistributedResultVo check(DistributedVo distributedVo) {
        /*查询规则对象*/
        DistributedResultVo distributedResultVo = new DistributedResultVo();
        distributedResultVo.setAppId(distributedVo.getAppId());
        distributedResultVo.setInterfaceName(distributedVo.getInterfaceName());
        DistributedEnum.AUTH_RESULT_ENUM state = resetRuleValue(distributedVo);
        distributedResultVo.setState(state.getCode());
        return distributedResultVo;
    }

    /**
     * 按规则校验
     *
     * @param distributedVo
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM resetRuleValue(DistributedVo distributedVo) {
        BtChargeManagement chargeManagement = getBtChargeManagement(distributedVo);
        if (null == chargeManagement) {
            //未授权，直接拒绝
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_DENIED;
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        if (chargeManagement.getEffectiveDate().isAfter(localDateTime) || chargeManagement.getExpirationDate().isBefore(localDateTime)) {
            //当前日期在生效日期之前或失效日期之后，则提示未生效或已失效
            return DistributedEnum.AUTH_RESULT_ENUM.AUTHORIZED_EXPIRATION;
        }
        /*策略执行*/
        if (DistributedEnum.RESETRULE_ENUM.DAY.getCode().equals(chargeManagement.getResetRule())) {
            /*按天重置*/
            return byDay(distributedVo, chargeManagement);
        } else if (DistributedEnum.RESETRULE_ENUM.WEEK.getCode().equals(chargeManagement.getResetRule())) {
            /*按周重置*/
            return byWeek(distributedVo, chargeManagement);
        } else if (DistributedEnum.RESETRULE_ENUM.MONTH.getCode().equals(chargeManagement.getResetRule())) {
            /*按月重置*/
            return byMonth(distributedVo, chargeManagement);
        } else if (DistributedEnum.RESETRULE_ENUM.YEAR.getCode().equals(chargeManagement.getResetRule())) {
            /*按年重置*/
            return byYear(distributedVo, chargeManagement);
        } else if (DistributedEnum.RESETRULE_ENUM.TOTAL.getCode().equals(chargeManagement.getResetRule())) {
            /*按总量统计*/
            return byTotal(distributedVo, chargeManagement);
        } else if (DistributedEnum.RESETRULE_ENUM.UNLIMITED.getCode().equals(chargeManagement.getResetRule())) {
            /*无限制使用*/
            return byUnlimited(distributedVo, chargeManagement);
        } else {
            /*授权规则配置错误，拒绝*/
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_DENIED;
        }
    }

    /**
     * 按天的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byDay(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        //计算下一周期开始时间
        LocalDateTime nextCycleStartTime = chargeManagement.getCycleTime().plusDays(1);
        /*2、若需要扣减次数，则进行以下校验*/
        /** 2.1、校验周期时间距离现在是否已经达到了一个周期，若达到刷新周期，则：
         *  a：校验：重置次数是否大于0，若小于等于0，则直接返回：使用次数不足，同时更新周期时间、更新时间
         *  b：可用次数 = 重置次数 - 1
         *  c：更新周期时间 = 当前周期时间（需要计算从开始周期到当前周期的时间值）
         *  d：总使用次数 = 总使用次数 + 本周期使用次数
         *  e：本周期使用次数 = 1
         *  f：修改时间 = 当前时间
         */
        boolean updateFlag = true;
        DistributedEnum.AUTH_RESULT_ENUM result = null;
        if(nextCycleStartTime.isBefore(LocalDateTime.now())) {
            //如果下一周期的开始时间 < 当前时间了，则说明周期要更新
            //根据周期时间，增加周期，直到大于当前时间，则获取到当前周期结束时间
            LocalDateTime cycleTime = chargeManagement.getCycleTime();
            while (cycleTime.isBefore(LocalDateTime.now())) {
                //每种计算不相同
                cycleTime = cycleTime.plusDays(1);
            }
            /*减掉一个周期，则取到了本周期的开始时间*/
            cycleTime = cycleTime.minusDays(1);
            if(chargeManagement.getResetCount() > 0) {
                updateFlag = allowAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                /*使用次数不足*/
                updateFlag = insufficientAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        } else {
            /**
             * 2.2、若未达到更新周期，则校验可用次数是否 > 0，若大于0，则：
             * a：可用次数 = 可用次数 - 1
             * b: 修改时间 = 当前时间
             * c: 本周期使用次数 = 本周期使用次数 + 1
             * 否则返回：使用次数不足
             */
            if(chargeManagement.getUsableCount() > 0) {
                //可用次数大于0
                updateFlag = allowAccessUpdate(chargeManagement);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                //可用次数不足
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        }
        /*3、根据条件进行更新操作，旧对象中的值作为更新条件，新对象中的值作为最新更新结果，若更新成功则记录免计费周期数据记录，同时返回“允许访问，减少次数”，若更新失败，则调用resetRuleValue方法递归执行*/
        if(updateFlag) {
            feeFreeCycleComponent.addRecord(distributedVo);
            return result;
        }
        return resetRuleValue(distributedVo);
    }

    /**
     * 按周的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byWeek(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        //计算下一周期开始时间
        LocalDateTime nextCycleStartTime = chargeManagement.getCycleTime().plusWeeks(1);
        /*2、若需要扣减次数，则进行以下校验*/
        /** 2.1、校验周期时间距离现在是否已经达到了一个周期，若达到刷新周期，则：
         *  a：校验：重置次数是否大于0，若小于等于0，则直接返回：使用次数不足，同时更新周期时间、更新时间
         *  b：可用次数 = 重置次数 - 1
         *  c：更新周期时间 = 当前周期时间（需要计算从开始周期到当前周期的时间值）
         *  d：总使用次数 = 总使用次数 + 本周期使用次数
         *  e：本周期使用次数 = 1
         *  f：修改时间 = 当前时间
         */
        boolean updateFlag = true;
        DistributedEnum.AUTH_RESULT_ENUM result = null;
        if(nextCycleStartTime.isBefore(LocalDateTime.now())) {
            //如果下一周期的开始时间 < 当前时间了，则说明周期要更新
            //根据周期时间，增加周期，直到大于当前时间，则获取到当前周期结束时间
            LocalDateTime cycleTime = chargeManagement.getCycleTime();
            while (cycleTime.isBefore(LocalDateTime.now())) {
                //每种计算不相同
                cycleTime = cycleTime.plusWeeks(1);
            }
            /*减掉一个周期，则取到了本周期的开始时间*/
            cycleTime = cycleTime.minusWeeks(1);
            if(chargeManagement.getResetCount() > 0) {
                updateFlag = allowAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                /*使用次数不足*/
                updateFlag = insufficientAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        } else {
            /**
             * 2.2、若未达到更新周期，则校验可用次数是否 > 0，若大于0，则：
             * a：可用次数 = 可用次数 - 1
             * b: 修改时间 = 当前时间
             * c: 本周期使用次数 = 本周期使用次数 + 1
             * 否则返回：使用次数不足
             */
            if(chargeManagement.getUsableCount() > 0) {
                //可用次数大于0
                updateFlag = allowAccessUpdate(chargeManagement);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                //可用次数不足
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        }
        /*3、根据条件进行更新操作，旧对象中的值作为更新条件，新对象中的值作为最新更新结果，若更新成功则记录免计费周期数据记录，同时返回“允许访问，减少次数”，若更新失败，则调用resetRuleValue方法递归执行*/
        if(updateFlag) {
            feeFreeCycleComponent.addRecord(distributedVo);
            return result;
        }
        return resetRuleValue(distributedVo);
    }

    /**
     * 按月的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byMonth(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        //计算下一周期开始时间
        LocalDateTime nextCycleStartTime = chargeManagement.getCycleTime().plusMonths(1);
        /*2、若需要扣减次数，则进行以下校验*/
        /** 2.1、校验周期时间距离现在是否已经达到了一个周期，若达到刷新周期，则：
         *  a：校验：重置次数是否大于0，若小于等于0，则直接返回：使用次数不足，同时更新周期时间、更新时间
         *  b：可用次数 = 重置次数 - 1
         *  c：更新周期时间 = 当前周期时间（需要计算从开始周期到当前周期的时间值）
         *  d：总使用次数 = 总使用次数 + 本周期使用次数
         *  e：本周期使用次数 = 1
         *  f：修改时间 = 当前时间
         */
        boolean updateFlag = true;
        DistributedEnum.AUTH_RESULT_ENUM result = null;
        if(nextCycleStartTime.isBefore(LocalDateTime.now())) {
            //如果下一周期的开始时间 < 当前时间了，则说明周期要更新
            //根据周期时间，增加周期，直到大于当前时间，则获取到当前周期结束时间
            LocalDateTime cycleTime = chargeManagement.getCycleTime();
            while (cycleTime.isBefore(LocalDateTime.now())) {
                //每种计算不相同
                cycleTime = cycleTime.plusMonths(1);
            }
            /*减掉一个周期，则取到了本周期的开始时间*/
            cycleTime = cycleTime.minusMonths(1);
            if(chargeManagement.getResetCount() > 0) {
                updateFlag = allowAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                /*使用次数不足*/
                updateFlag = insufficientAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        } else {
            /**
             * 2.2、若未达到更新周期，则校验可用次数是否 > 0，若大于0，则：
             * a：可用次数 = 可用次数 - 1
             * b: 修改时间 = 当前时间
             * c: 本周期使用次数 = 本周期使用次数 + 1
             * 否则返回：使用次数不足
             */
            if(chargeManagement.getUsableCount() > 0) {
                //可用次数大于0
                updateFlag = allowAccessUpdate(chargeManagement);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                //可用次数不足
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        }
        /*3、根据条件进行更新操作，旧对象中的值作为更新条件，新对象中的值作为最新更新结果，若更新成功则记录免计费周期数据记录，同时返回“允许访问，减少次数”，若更新失败，则调用resetRuleValue方法递归执行*/
        if(updateFlag) {
            feeFreeCycleComponent.addRecord(distributedVo);
            return result;
        }
        return resetRuleValue(distributedVo);
    }

    /**
     * 按年的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byYear(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        //计算下一周期开始时间
        LocalDateTime nextCycleStartTime = chargeManagement.getCycleTime().plusYears(1);
        /*2、若需要扣减次数，则进行以下校验*/
        /** 2.1、校验周期时间距离现在是否已经达到了一个周期，若达到刷新周期，则：
         *  a：校验：重置次数是否大于0，若小于等于0，则直接返回：使用次数不足，同时更新周期时间、更新时间
         *  b：可用次数 = 重置次数 - 1
         *  c：更新周期时间 = 当前周期时间（需要计算从开始周期到当前周期的时间值）
         *  d：总使用次数 = 总使用次数 + 本周期使用次数
         *  e：本周期使用次数 = 1
         *  f：修改时间 = 当前时间
         */
        boolean updateFlag = true;
        DistributedEnum.AUTH_RESULT_ENUM result = null;
        if(nextCycleStartTime.isBefore(LocalDateTime.now())) {
            //如果下一周期的开始时间 < 当前时间了，则说明周期要更新
            //根据周期时间，增加周期，直到大于当前时间，则获取到当前周期结束时间
            LocalDateTime cycleTime = chargeManagement.getCycleTime();
            while (cycleTime.isBefore(LocalDateTime.now())) {
                //每种计算不相同
                cycleTime = cycleTime.plusYears(1);
            }
            /*减掉一个周期，则取到了本周期的开始时间*/
            cycleTime = cycleTime.minusYears(1);
            if(chargeManagement.getResetCount() > 0) {
                updateFlag = allowAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                /*使用次数不足*/
                updateFlag = insufficientAccessResetUpdate(chargeManagement, cycleTime);
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        } else {
            /**
             * 2.2、若未达到更新周期，则校验可用次数是否 > 0，若大于0，则：
             * a：可用次数 = 可用次数 - 1
             * b: 修改时间 = 当前时间
             * c: 本周期使用次数 = 本周期使用次数 + 1
             * 否则返回：使用次数不足
             */
            if(chargeManagement.getUsableCount() > 0) {
                //可用次数大于0
                updateFlag = allowAccessUpdate(chargeManagement);
                result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
            } else {
                //可用次数不足
                result = DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
            }
        }
        /*3、根据条件进行更新操作，旧对象中的值作为更新条件，新对象中的值作为最新更新结果，若更新成功则记录免计费周期数据记录，同时返回“允许访问，减少次数”，若更新失败，则调用resetRuleValue方法递归执行*/
        if(updateFlag) {
            feeFreeCycleComponent.addRecord(distributedVo);
            return result;
        }
        return resetRuleValue(distributedVo);
    }


    /**
     * 按总次数的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byTotal(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        boolean updateFlag = false;
        DistributedEnum.AUTH_RESULT_ENUM result = null;
        if(chargeManagement.getUsableCount() > 0) {
            //可用次数大于0
            updateFlag = allowAccessUpdate(chargeManagement);
            result = DistributedEnum.AUTH_RESULT_ENUM.ACCESS_ALLOW;
        } else {
            //可用次数不足
            return DistributedEnum.AUTH_RESULT_ENUM.INSUFFICIENT_FREQUENCY;
        }
        /*3、根据条件进行更新操作，旧对象中的值作为更新条件，新对象中的值作为最新更新结果，若更新成功则记录免计费周期数据记录，同时返回“允许访问，减少次数”，若更新失败，则调用resetRuleValue方法递归执行*/
        if(updateFlag) {
            feeFreeCycleComponent.addRecord(distributedVo);
            return result;
        }
        return resetRuleValue(distributedVo);
    }

    /**
     * 无限制的策略
     *
     * @return
     */
    public DistributedEnum.AUTH_RESULT_ENUM byUnlimited(DistributedVo distributedVo, BtChargeManagement chargeManagement) {
        /*1、校验是否可免次数调用，若允许则直接返回“允许访问，不减次数”*/
        if(feeFreeCycleComponent.checkCanFeeFree(distributedVo)) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        /*本周期使用次数+1*/
        BtChargeManagement oldValue = new BtChargeManagement();
        oldValue.setUpdateTime(chargeManagement.getUpdateTime());
        oldValue.setCurrentUsage(chargeManagement.getCurrentUsage());
        chargeManagement.setCurrentUsage(chargeManagement.getCurrentUsage() + 1);
        chargeManagement.setUpdateTime(LocalDateTime.now());
        boolean updateFlag = btChargeManagementService.update(chargeManagement, new UpdateWrapper<>(oldValue));
        if(updateFlag) {
            return DistributedEnum.AUTH_RESULT_ENUM.ACCESS_FRE_ALLOW;
        }
        return resetRuleValue(distributedVo);
    }

    /**
     * 允许访问不更新周期更新方法
     * @param chargeManagement
     * @return
     */
    private boolean allowAccessUpdate(BtChargeManagement chargeManagement) {
        BtChargeManagement oldValue = new BtChargeManagement();
        oldValue.setId(chargeManagement.getId());
        oldValue.setUsableCount(chargeManagement.getUsableCount());
        oldValue.setCycleTime(chargeManagement.getCycleTime());
        oldValue.setCurrentUsage(chargeManagement.getCurrentUsage());
        oldValue.setDelInd(chargeManagement.getDelInd());
        oldValue.setUpdateTime(chargeManagement.getUpdateTime());

        chargeManagement.setUsableCount(chargeManagement.getUsableCount() - 1);
        chargeManagement.setCurrentUsage(chargeManagement.getCurrentUsage() + 1);
        chargeManagement.setUpdateTime(LocalDateTime.now());
        return btChargeManagementService.update(chargeManagement, new UpdateWrapper<>(oldValue));
    }

    /**
     * 不允许访问周期刷新更新方法
     * @param chargeManagement
     * @param cycleTime 当前周期开始时间
     * @return
     */
    private boolean insufficientAccessResetUpdate(BtChargeManagement chargeManagement, LocalDateTime cycleTime) {
        BtChargeManagement oldValue = new BtChargeManagement();
        oldValue.setId(chargeManagement.getId());
        oldValue.setUsableCount(chargeManagement.getUsableCount());
        oldValue.setResetCount(chargeManagement.getResetCount());
        oldValue.setCycleTime(chargeManagement.getCycleTime());
        oldValue.setTotalUsage(chargeManagement.getTotalUsage());
        oldValue.setCurrentUsage(chargeManagement.getCurrentUsage());
        oldValue.setUpdateTime(chargeManagement.getUpdateTime());

        chargeManagement.setUsableCount(0);
        chargeManagement.setCycleTime(cycleTime);
        chargeManagement.setTotalUsage(chargeManagement.getTotalUsage() + chargeManagement.getCurrentUsage());
        chargeManagement.setCurrentUsage(0);
        chargeManagement.setUpdateTime(LocalDateTime.now());
        return btChargeManagementService.update(chargeManagement, new UpdateWrapper<>(oldValue));
    }

    /**
     * 允许访问周期更新方法
     * @param chargeManagement
     * @param cycleTime 当前周期开始时间
     * @return
     */
    private boolean allowAccessResetUpdate(BtChargeManagement chargeManagement, LocalDateTime cycleTime) {
        BtChargeManagement oldValue = new BtChargeManagement();
        oldValue.setId(chargeManagement.getId());
        oldValue.setUsableCount(chargeManagement.getUsableCount());
        oldValue.setResetCount(chargeManagement.getResetCount());
        oldValue.setCycleTime(chargeManagement.getCycleTime());
        oldValue.setTotalUsage(chargeManagement.getTotalUsage());
        oldValue.setCurrentUsage(chargeManagement.getCurrentUsage());
        oldValue.setUpdateTime(chargeManagement.getUpdateTime());

        chargeManagement.setUsableCount(chargeManagement.getResetCount() - 1);
        chargeManagement.setCycleTime(cycleTime);
        chargeManagement.setTotalUsage(chargeManagement.getTotalUsage() + chargeManagement.getCurrentUsage());
        chargeManagement.setCurrentUsage(1);
        chargeManagement.setUpdateTime(LocalDateTime.now());
        return btChargeManagementService.update(chargeManagement, new UpdateWrapper<>(oldValue));
    }

}
